#include "seek.h"

#include <cassert> // assert
#include <limits> // std::numeric_limits

#include <unistd.h> // ::lseek SEEK_END SEEK_SET off_t
#include <errno.h> // errno ESPIPE

namespace simple::io
{

	[[nodiscard]]
	seek_result seek(const unique_handle& handle, std::size_t offset) noexcept
	{
		assert(std::numeric_limits<off_t>::max() >= offset);
		assert(handle != nullptr);
		int fd = static_cast<int>(static_cast<enum handle>(handle.get()));

		auto result = ::lseek(fd, offset, SEEK_SET);
		if(-1 == result)
		{
			switch(errno)
			{
				case ESPIPE: return not_seekable{errno};
				default: return error{errno};
			}
		}

		assert(result >= 0);
		assert(static_cast<std::size_t>(result) == offset);

		return seek_result{};
	}

	[[nodiscard]]
	size_result size(const unique_handle& handle) noexcept
	{
		assert(handle != nullptr);
		int fd = static_cast<int>(static_cast<enum handle>(handle.get()));

		auto result = ::lseek(fd, 0, SEEK_END);
		if(-1 == result)
		{
			switch(errno)
			{
				case ESPIPE: return not_seekable{errno};
				default: return error{errno};
			}
		}

		assert(result >= 0);

		return static_cast<std::size_t>(result);
	}

} // namespace simple::io
